/*************************************************************************
 *
 * Copyright (c) 2009-2014 Xuld. All rights reserved.
 * 
 * Project Url: http://work.xuld.net/circus
 * 
 * This source code is part of the Project Circus.
 * 
 * This code is licensed under The Circus License.
 * See the file License.html for the license details.
 * 
 * 
 * You must not remove this notice, or any other, from this software.
 *
 * 
 *************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

namespace Circus.Utility {

    /// <summary>
    /// 表示一个简易的计算器。
    /// </summary>
    /// <remarks>
    /// <example>
    /// 以下示例演示了如何使用 <see cref="Computer"/> 计算表达式。
    /// <code>
    /// using System;
    /// using Circus.Utility;
    /// 
    /// class Sample{
    /// 
    ///     public static void Main(){
    ///         Arithmetic calc = new Arithmetic();
    ///         double result = calc.compute("1 + 2sin 4");
    ///         Console.Write(result);
    ///         Console.Read();
    ///     }
    /// }
    /// </code>
    /// 一个表达式中的函数可自定义。
    /// 以下演示了如何自定义函数。
    /// <code>
    /// using System;
    /// using Circus.Utility;
    /// 
    /// class Sample{
    /// 
    ///     public static void Main(){
    ///         Arithmetic.operators["in"] = new InOperator();
    ///         Arithmetic calc = new Arithmetic();
    ///         double result = calc.compute("1 + ln 4");
    ///         Console.Write(result); // 6
    ///         Console.Read();
    ///     }
    /// }
    /// </code>
    /// </example>
    /// </remarks>
    public sealed class Computer {

        #region 操作符

        /// <summary>
        /// 表示一个操作符。
        /// </summary>
        public interface IOperator {

            /// <summary>
            /// 获取当前操作符的优先等级。
            /// </summary>
            int precedence {
                get;
            }

            /// <summary>
            /// 判断当前操作符是否是常数。
            /// </summary>
            bool isConst {
                get;
            }

            /// <summary>
            /// 判断当前操作符是否是前缀单目操作符。
            /// </summary>
            bool isPrefixUnary {
                get;
            }

            /// <summary>
            /// 判断当前操作符是否是前缀单目操作符。
            /// </summary>
            bool isPostfixUnary {
                get;
            }

            /// <summary>
            /// 判断当前操作符是否是双目操作符。
            /// </summary>
            bool isBinary {
                get;
            }

            /// <summary>
            /// 获取当前操作符的名称。
            /// </summary>
            /// <returns></returns>
            string ToString();

            /// <summary>
            /// 通过当前操作符计算指定操作数的值。
            /// </summary>
            /// <param name="operand">要计算的值。</param>
            /// <returns>计算的结果。</returns>
            double compute(double operand);

            /// <summary>
            /// 通过当前操作符计算指定操作数的值。
            /// </summary>
            /// <param name="leftOperand">左操作值。</param>
            /// <param name="rightOperand">右操作值。</param>
            /// <returns>计算的结果。</returns>
            double compute(double leftOperand, double rightOperand);


        }

        /// <summary>
        /// 获取所有可用的操作符。
        /// </summary>
        public static readonly Dictionary<string, IOperator> operators = new Dictionary<string, IOperator>();

        #endregion

        #region 词法解析

        /// <summary>
        /// 当前正在解析的输入表达式。
        /// </summary>
        private string currentInput;

        /// <summary>
        /// 当前已解析的位置。
        /// </summary>
        private int currentLocation;

        /// <summary>
        /// 获取或设置所有可用的变量。
        /// </summary>
        public Dictionary<string, double> variables;

        /// <summary>
        /// 扫描下一个操作符。
        /// </summary>
        /// <returns>返回操作符。</returns>
        private IOperator scan() {

            // 读取完毕。
            int length = currentInput.Length;
        skip:
            if (currentLocation >= length) {
                return null;
            }

            char c = currentInput[currentLocation];

            // 读取数字。
        readAsNum:
            if (c >= '0' && c <= '9') {
                // 读取整数部分。
                double value = 0;
                do {
                    value = value * 10 + (c - '0');
                } while (++currentLocation < length && (c = currentInput[currentLocation]) >= '0' && c <= '9');

                // 读取小数部分。
                if (c == '.') {
                    double baseValue = 1;
                    while (++currentLocation < length && (c = currentInput[currentLocation]) >= '0' && c <= '9') {
                        baseValue *= 10;
                        value += (c - '0') / baseValue;
                    }
                }

                return new NumberLiteralExpression() {
                    value = value
                };
            }

            switch (c) {

                // 忽略空格。
                case ' ':
                case '\t':
                case '\r':
                case '\n':
                    currentLocation++;
                    goto skip;

                case '.':
                    c = '0';
                    currentLocation--;
                    goto readAsNum;

                default:
                    string operatorName;

                    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                        c = (char)(c | 0x20);
                        StringBuilder sb = new StringBuilder();
                        do {
                            sb.Append(c);
                        } while (++currentLocation < length && (c = (char)(currentInput[currentLocation] | 0x20)) >= 'a' && c <= 'z');

                        operatorName = sb.ToString();
                    } else {
                        currentLocation++;
                        operatorName = c.ToString();
                    }

                    // 作为变量解析。
                    double value;
                    if (variables != null && variables.TryGetValue(operatorName, out value)) {
                        return new NumberLiteralExpression() {
                            value = value
                        };
                    }

                    IOperator op;
                    if (operators.TryGetValue(operatorName, out op)) {
                        return op;
                    }

                    throw new ArithmeticException("找不到名为“" + operatorName + "”的变量、操作符或函数");

            }

        }

        #endregion

        #region 语法解析

        /// <summary>
        /// 获取当前的操作符。
        /// </summary>
        private IOperator currentOperator;

        private void read() {
            currentOperator = scan();
        }

        /// <summary>
        /// 解析一个表达式。
        /// </summary>
        /// <param name="minPrecedence">当前解析的最低操作符优先级。</param>
        /// <returns></returns>
        private Expression parseExpression(int minPrecedence) {
            if (currentOperator == null) {
                return null;
            }

            Expression parsed;
            if (currentOperator.isConst) {
                // 解析常量。
                parsed = currentOperator as Expression ?? new NumberLiteralExpression() {
                    value = currentOperator.compute(0D)
                };
                read();
            } else if (currentOperator.isPrefixUnary) {
                // 解析前缀单目运算符。
                var op = currentOperator;
                read();
                var right = parseExpression(op.precedence);
                if (currentOperator == operators[")"]) {
                    read();
                }
                if (currentOperator == operators[","]) {
                    read();
                    parsed = new BinaryExpression() {
                        @operator = op,
                        leftOperand = right,
                        rightOperand = parseExpression(op.precedence)
                    };
                } else {
                    parsed = new UnaryExpression() {
                        @operator = op,
                        operand = right
                    };
                }
            } else if (currentOperator == operators["("]) {
                // 解析括号。
                read();
                parsed = parseExpression(0);
                if (currentOperator == operators[")"]) {
                    read();
                }
            } else if (currentOperator == operators[")"]) {
                throw new ArithmeticException("多余的“)”");
            } else {
                throw new ArithmeticException("“" + currentOperator.ToString() + "”操作符不能作为前缀表达式使用");
            }

            return parseExpression(parsed, minPrecedence);

        }

        /// <summary>
        /// 在解析一个表达式之后，继续解析剩下的后缀表达式。
        /// </summary>
        /// <param name="parsed">已解析的表达式。</param>
        /// <param name="minPrecedence">当前解析的最低操作符优先级。</param>
        /// <returns></returns>
        private Expression parseExpression(Expression parsed, int minPrecedence) {
        next:
            if ((currentOperator != null && currentOperator.precedence >= minPrecedence)) {

                // 解析后缀单目表达式。
                if (currentOperator.isPostfixUnary) {
                    parsed = new UnaryExpression() {
                        operand = parsed,
                        @operator = currentOperator
                    };
                    read();
                    goto next;
                }

                Expression right;
                IOperator op;

                if (currentOperator.isBinary) {
                    op = currentOperator;
                    read();
                } else {
                    // 如果当前表达式不是合法双目运算符，则作为 * 表达式。
                    op = operators["*"];
                }

                right = parseExpression(op.precedence + 1);
                if (right == null) {
                    throw new ArithmeticException("“" + op.ToString() + "”操作符需要两个操作数");
                }

                parsed = new BinaryExpression() {
                    leftOperand = parsed,
                    @operator = op,
                    rightOperand = right
                };
                goto next;
            }

            return parsed;
        }

        /// <summary>
        /// 表示一个表达式。
        /// </summary>
        private abstract class Expression {

            /// <summary>
            /// 当被子类重写时，负责计算当前表达式的值。
            /// </summary>
            /// <returns>返回计算后的值。</returns>
            public abstract double compute();

        }

        /// <summary>
        /// 表示一个数值常量表达式。
        /// </summary>
        private sealed class NumberLiteralExpression : Expression, IOperator {

            /// <summary>
            /// 获取或设置当前表达式的值。
            /// </summary>
            public double value;

            /// <summary>
            /// 当被子类重写时，负责计算当前表达式的值。
            /// </summary>
            /// <returns>返回计算后的值。</returns>
            public override double compute() {
                return value;
            }

            int IOperator.precedence {
                get {
                    return 82;
                }
            }

            bool IOperator.isConst {
                get {
                    return true;
                }
            }

            bool IOperator.isPrefixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isPostfixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isBinary {
                get {
                    return false;
                }
            }

            double IOperator.compute(double operand) {
                return value;
            }

            double IOperator.compute(double leftOperand, double rightOperand) {
                return value;
            }

            public override string ToString() {
                return value.ToString();
            }
        }

        /// <summary>
        /// 表示一个单目运算符。
        /// </summary>
        private sealed class UnaryExpression : Expression {

            /// <summary>
            /// 获取当前操作符。
            /// </summary>
            public IOperator @operator;

            /// <summary>
            /// 获取左操作数。
            /// </summary>
            public Expression operand;

            /// <summary>
            /// 当被子类重写时，负责计算当前表达式的值。
            /// </summary>
            /// <returns>返回计算后的值。</returns>
            public override double compute() {
                return @operator.compute(operand.compute());
            }

        }

        /// <summary>
        /// 表示一个双目运算符。
        /// </summary>
        private sealed class BinaryExpression : Expression {

            /// <summary>
            /// 获取当前操作符。
            /// </summary>
            public IOperator @operator;

            /// <summary>
            /// 获取左操作数。
            /// </summary>
            public Expression leftOperand;

            /// <summary>
            /// 获取右操作数。
            /// </summary>
            public Expression rightOperand;

            /// <summary>
            /// 当被子类重写时，负责计算当前表达式的值。
            /// </summary>
            /// <returns>返回计算后的值。</returns>
            public override double compute() {
                return @operator.compute(leftOperand.compute(), rightOperand.compute());
            }

        }

        /// <summary>
        /// 表示一个左括号。
        /// </summary>
        private sealed class LeftParentheses : IOperator {

            int IOperator.precedence {
                get {
                    return 80;
                }
            }

            bool IOperator.isConst {
                get {
                    return false;
                }
            }

            bool IOperator.isPrefixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isPostfixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isBinary {
                get {
                    return false;
                }
            }

            double IOperator.compute(double operand) {
                throw new InvalidOperationException();
            }

            double IOperator.compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "(";
            }

        }

        /// <summary>
        /// 表示一个右括号。
        /// </summary>
        private sealed class RightParentheses : IOperator {

            int IOperator.precedence {
                get {
                    return -2;
                }
            }

            bool IOperator.isConst {
                get {
                    return false;
                }
            }

            bool IOperator.isPrefixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isPostfixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isBinary {
                get {
                    return false;
                }
            }

            double IOperator.compute(double operand) {
                throw new InvalidOperationException();
            }

            double IOperator.compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return ")";
            }

        }

        /// <summary>
        /// 表示一个逗号。
        /// </summary>
        private sealed class Comma : IOperator {

            int IOperator.precedence {
                get {
                    return -2;
                }
            }

            bool IOperator.isConst {
                get {
                    return false;
                }
            }

            bool IOperator.isPrefixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isPostfixUnary {
                get {
                    return false;
                }
            }

            bool IOperator.isBinary {
                get {
                    return false;
                }
            }

            double IOperator.compute(double operand) {
                throw new InvalidOperationException();
            }

            double IOperator.compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return ",";
            }

        }

        #endregion

        #region 计算

        /// <summary>
        /// 计算指定的表达式。
        /// </summary>
        /// <param name="expression">表达式。</param>
        /// <returns>计算的结果。</returns>
        /// <exception cref="ArithmeticException">无法计算表达式的值时引发此错误。</exception>
        public double compute(string expression) {
            currentInput = expression;
            currentLocation = 0;
            read();
            var p = parseExpression(0);
            if (p == null) {
                return 0D;
            }
            return p.compute();
        }

        /// <summary>
        /// 计算指定的表达式。
        /// </summary>
        /// <param name="expression">表达式。</param>
        /// <returns>计算的结果。</returns>
        /// <exception cref="ArithmeticException">无法计算表达式的值时引发此错误。</exception>
        public static double computeExpression(string expression) {
            return new Computer().compute(expression);
        }

        /// <summary>
        /// 计算指定的表达式。
        /// </summary>
        /// <param name="expression">表达式。</param>
        /// <param name="defaultValue">如果计算发生错误，则返回此默认值。</param>
        /// <returns>计算的结果。</returns>
        public static double computeExpression(string expression, double defaultValue) {
            try {
                return new Computer().compute(expression);
            } catch {
                return defaultValue;
            }
        }

        #endregion

        #region 内置操作符

        static Computer() {
            operators["("] = operators["（"] = new LeftParentheses();
            operators[")"] = operators["）"] = new RightParentheses();
            operators[","] = operators["，"] = new Comma();

            operators["+"] = operators["＋"] = new AddOperator();
            operators["-"] = operators["－"] = new SubOperator();
            operators["*"] = operators["×"] = new MulOperator();
            operators["/"] = operators["／"] = operators["÷"] = new DivOperator();

            operators["\\"] = operators["|"] = new ExactDivOperator();
            operators["^"] = operators["∧"] = new PowOperator();
            operators["%"] = operators["％"] = new PercentOperator();
            operators["‰"] = new TPercentOperator();
            operators["!"] = operators["！"] = new FactorialOperator();

            operators["√"] = new SqrtOperator();
            operators["²"] = new Pow2Operator();
            operators["³"] = new Pow3Operator();

            operators["pi"] = operators["π"] = new PIOperator();
            operators["e"] = new EOperator();
            operators["∞"] = new InfinityOperator();

            operators["abs"] = new AbsOperator();
            operators["arccos"] = new ArccosOperator();

            operators["arccos"] = new ArccosOperator();
            operators["arcsin"] = new ArcsinOperator();
            operators["arctan"] = new ArctanOperator();
            operators["arccot"] = new ArccotOperator();
            operators["ceil"] = new CeilOperator();
            operators["cos"] = new CosOperator();
            operators["cosh"] = new CoshOperator();
            operators["cot"] = new CotOperator();
            operators["coth"] = new CothOperator();
            operators["exp"] = new ExpOperator();
            operators["floor"] = new FloorOperator();
            operators["log"] = operators["lg"] = operators["㏒"] = new LogOperator();
            operators["ln"] = operators["㏑"] = new LnOperator();
            operators["max"] = new MaxOperator();
            operators["mod"] = new ModOperator();
            operators["min"] = new MinOperator();
            operators["round"] = new RoundOperator();
            operators["sin"] = new SinOperator();
            operators["sinh"] = new SinhOperator();
            operators["tan"] = new TanOperator();
            operators["tanh"] = new TanhOperator();

            operators["and"] = new AndOperator();
            operators["or"] = new OrOperator();
            operators["not"] = new NotOperator();
        }

        private sealed class AddOperator : IOperator {

            public int precedence {
                get {
                    return 34;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return true;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                return operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand + rightOperand;
            }

            public override string ToString() {
                return "+";
            }

        }

        private sealed class SubOperator : IOperator {

            public int precedence {
                get {
                    return 34;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return true;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                return -operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand - rightOperand;
            }

            public override string ToString() {
                return "-";
            }

        }

        private sealed class MulOperator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand * rightOperand;
            }

            public override string ToString() {
                return "*";
            }

        }

        private sealed class DivOperator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand / rightOperand;
            }

            public override string ToString() {
                return "/";
            }

        }

        private sealed class PowOperator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public double compute(double leftOperand, double rightOperand) {
                return Math.Pow(leftOperand, rightOperand);
            }

            public override string ToString() {
                return "^";
            }

        }

        private sealed class Pow2Operator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return true;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return operand * operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "²";
            }

        }

        private sealed class Pow3Operator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return true;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return operand * operand * operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "³";
            }

        }

        private sealed class SqrtOperator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return true;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return Math.Sqrt(operand);
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "√";
            }

        }

        private sealed class ExactDivOperator : IOperator {

            public int precedence {
                get {
                    return 36;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public double compute(double leftOperand, double rightOperand) {
                return Math.Truncate(leftOperand / rightOperand);
            }

            public override string ToString() {
                return "|";
            }

        }

        private sealed class PercentOperator : IOperator {

            public int precedence {
                get {
                    return 18;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return true;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return operand / 100;
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "%";
            }

        }

        private sealed class FactorialOperator : IOperator {

            public int precedence {
                get {
                    return 18;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return true;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                if (operand < 2) {
                    if (operand < 1) {
                        return double.NaN;
                    }
                    return 1D;
                }
                double result = 1D;
                for (int i = 2; i <= operand; i++) {
                    result *= i;
                }
                return result;
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "!";
            }

        }

        private sealed class TPercentOperator : IOperator {

            public int precedence {
                get {
                    return 18;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return true;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return operand / 1000;
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

            public override string ToString() {
                return "‰";
            }

        }

        private abstract class ConstOperator {

            public int precedence {
                get {
                    return 80;
                }
            }

            public bool isConst {
                get {
                    return true;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

        }

        private sealed class PIOperator : ConstOperator, IOperator {

            public double compute(double operand) {
                return Math.PI;
            }

            public override string ToString() {
                return "pi";
            }

        }

        private sealed class EOperator : ConstOperator, IOperator {

            public double compute(double operand) {
                return Math.E;
            }

            public override string ToString() {
                return "e";
            }

        }

        private sealed class InfinityOperator : ConstOperator, IOperator {

            public double compute(double operand) {
                return double.NegativeInfinity;
            }

            public override string ToString() {
                return "∞";
            }

        }

        private abstract class FuncOperator {

            public int precedence {
                get {
                    return 60;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return true;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double leftOperand, double rightOperand) {
                throw new InvalidOperationException();
            }

        }

        private sealed class AbsOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Abs(operand);
            }

            public override string ToString() {
                return "abs";
            }

        }

        private sealed class ArccosOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Acos(operand);
            }

            public override string ToString() {
                return "arccos";
            }

        }

        private sealed class ArcsinOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Asin(operand);
            }

            public override string ToString() {
                return "arcsin";
            }

        }

        private sealed class ArctanOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Atan(operand);
            }

            public override string ToString() {
                return "arctan";
            }

        }

        private sealed class ArccotOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return 1 / Math.Atan(operand);
            }

            public override string ToString() {
                return "arccot";
            }

        }

        private sealed class CeilOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Ceiling(operand);
            }

            public override string ToString() {
                return "ceil";
            }

        }

        private sealed class CosOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Cos(operand);
            }

            public override string ToString() {
                return "cos";
            }

        }

        private sealed class CoshOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Cosh(operand);
            }

            public override string ToString() {
                return "cosh";
            }

        }

        private sealed class CotOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return 1 / Math.Tan(operand);
            }

            public override string ToString() {
                return "cot";
            }

        }

        private sealed class CothOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return 1 / Math.Tanh(operand);
            }

            public override string ToString() {
                return "coth";
            }

        }

        private sealed class ExpOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Exp(operand);
            }

            public override string ToString() {
                return "exp";
            }

        }

        private sealed class FloorOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Floor(operand);
            }

            public override string ToString() {
                return "floor";
            }

        }

        private sealed class LogOperator : FuncOperator, IOperator {

            public new bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                return Math.Log(operand);
            }

            public new double compute(double leftOperand, double rightOperand) {
                return Math.Log(rightOperand, leftOperand);
            }

            public override string ToString() {
                return "log";
            }

        }

        private sealed class LnOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Log10(operand);
            }

            public override string ToString() {
                return "ln";
            }

        }

        private sealed class MaxOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public new bool isBinary {
                get {
                    return true;
                }
            }

            public new double compute(double leftOperand, double rightOperand) {
                return Math.Max(leftOperand, rightOperand);
            }

            public override string ToString() {
                return "max";
            }

        }

        private sealed class ModOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public new bool isBinary {
                get {
                    return true;
                }
            }

            public new double compute(double leftOperand, double rightOperand) {
                return leftOperand % rightOperand;
            }

            public override string ToString() {
                return "mod";
            }

        }

        private sealed class MinOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                throw new InvalidOperationException();
            }

            public new bool isBinary {
                get {
                    return true;
                }
            }

            public new double compute(double leftOperand, double rightOperand) {
                return Math.Min(leftOperand, rightOperand);
            }

            public override string ToString() {
                return "min";
            }

        }

        private sealed class RoundOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Round(operand);
            }

            public override string ToString() {
                return "round";
            }

        }

        private sealed class SinOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Sin(operand);
            }

            public override string ToString() {
                return "sin";
            }

        }

        private sealed class SinhOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Sinh(operand);
            }

            public override string ToString() {
                return "sinh";
            }

        }

        private sealed class TanOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Tan(operand);
            }

            public override string ToString() {
                return "tan";
            }

        }

        private sealed class TanhOperator : FuncOperator, IOperator {

            public double compute(double operand) {
                return Math.Tanh(operand);
            }

            public override string ToString() {
                return "tanh";
            }

        }

        private sealed class AndOperator : IOperator {

            public int precedence {
                get {
                    return 28;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                return operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand != 0d && rightOperand != 0d ? 1d : 0d;
            }

            public override string ToString() {
                return "and";
            }

        }

        private sealed class OrOperator : IOperator {

            public int precedence {
                get {
                    return 30;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return false;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return true;
                }
            }

            public double compute(double operand) {
                return operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand != 0d || rightOperand != 0d ? 1d : 0d;
            }

            public override string ToString() {
                return "or";
            }

        }

        private sealed class NotOperator : IOperator {

            public int precedence {
                get {
                    return 60;
                }
            }

            public bool isConst {
                get {
                    return false;
                }
            }

            public bool isPrefixUnary {
                get {
                    return true;
                }
            }

            public bool isPostfixUnary {
                get {
                    return false;
                }
            }

            public bool isBinary {
                get {
                    return false;
                }
            }

            public double compute(double operand) {
                return operand;
            }

            public double compute(double leftOperand, double rightOperand) {
                return leftOperand == 0d ? 1d : 0d;
            }

            public override string ToString() {
                return "not";
            }

        }

        #endregion

    }
}
